//
//  Copyright (C) 2009 Vadim Ushakov
// 
//  This program is free software; you can redistribute it and/or modify it
//  under the terms of the GNU General Public License as published by the Free
//  Software Foundation; either version 2 of the License, or (at your option)
//  any later version.
// 
//  This program is distributed in the hope that it will be useful, but
//  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
//  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
//  for more details.
//  
//  You should have received a copy of the GNU General Public License along
//  with this program; if not, write to the Free Software Foundation, Inc.,
//  59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
//  kernelEnvironment.c
//

#include "kernelError.h"
#include "kernelLock.h"
#include "kernelPerformanceCounter.h"
#include <string.h>


#define PCOUNTER_NAME_SIZE 64
#define PCOUNTER_NUM 256
static struct 
{
	int64_t value;
	char name[PCOUNTER_NAME_SIZE];
} performanceCounterList[PCOUNTER_NUM];
static int performanceCounters = 0;
static int performanceCountersInitialized = 0;
static LOCK_DECL(performanceCounterListLock);


static void kernelPerformanceCounterInitialize(void)
{
	performanceCountersInitialized = 1;
}

int kernelPerformanceCounterRegister(const char * name)
{
	int status = 0;
	int i;

	if (!name)
		return (status = ERR_NULLPARAMETER);

	if ((status = kernelLockAcquire(&performanceCounterListLock, -1)) < 0)
	{
		kernelError(kernel_error, "Failed register performance counter %s (no lock)", name);
		return (status);
	}

	if (!performanceCountersInitialized)
	{
		kernelPerformanceCounterInitialize();
	}

	for (i = 0; i < performanceCounters; i++)
	{
		if (strncmp(performanceCounterList[i].name, name, PCOUNTER_NAME_SIZE) == 0)
		{
			kernelLockRelease(&performanceCounterListLock);
			return i;
		}
	}

	if (i < PCOUNTER_NUM)
	{
		strncpy(performanceCounterList[i].name, name, PCOUNTER_NAME_SIZE);
		performanceCounters++;
		status = i;
	}
	else
	{
		kernelError(kernel_error, "Failed register performance counter %s (no free records)", name);
		status = ERR_NOFREE;
	}

	kernelLockRelease(&performanceCounterListLock);

	return (status = i);
}

int kernelPerformanceCounterGetIndex(const char *name)
{
	int status = 0;
	int i;

	if (!name)
		return (status = ERR_NULLPARAMETER);

	if ((status = kernelLockAcquire(&performanceCounterListLock, -1)) < 0)
		return (status);

	if (!performanceCountersInitialized)
	{
		kernelPerformanceCounterInitialize();
	}

	for (i = 0; i < performanceCounters; i++)
	{
		if (strncmp(performanceCounterList[i].name, name, PCOUNTER_NAME_SIZE) == 0)
		{
			kernelLockRelease(&performanceCounterListLock);
			return i;
		}
	}

	kernelLockRelease(&performanceCounterListLock);

	return (status = ERR_NOSUCHENTRY);
}


int kernelPerformanceCounterGetI(int index)
{
	return kernelPerformanceCounterGetI64(index);
}


int kernelPerformanceCounterSetI(int index, int value)
{
	return kernelPerformanceCounterSetI64(index, value);
}


int kernelPerformanceCounterIncI(int index, int value)
{
	return kernelPerformanceCounterIncI64(index, value);
}


int64_t kernelPerformanceCounterGetI64(int index)
{
	if (index < 0 || index >= performanceCounters)
		return (ERR_INVALID);
	return performanceCounterList[index].value;
}


int kernelPerformanceCounterSetI64(int index, int64_t value)
{
	int status;

	if (index < 0 || index >= performanceCounters)
		return (status = ERR_INVALID);

	performanceCounterList[index].value = value;

	return (status = 0);
}


int kernelPerformanceCounterIncI64(int index, int64_t value)
{
	int status;

	if (index < 0 || index >= performanceCounters)
		return (status = ERR_INVALID);

	performanceCounterList[index].value += value;

	return (status = 0);
}


int kernelPerformanceCounterInc1(int index)
{
	return kernelPerformanceCounterIncI(index, 1);
}


int kernelPerformanceListNames(char* buff, int buffSize)
{
	int status;

	int i;
	int size = 1;

	if (buffSize > 0 && buff == NULL)
		return (ERR_NULLPARAMETER);

	if ((status = kernelLockAcquire(&performanceCounterListLock, -1)) < 0)
		return (status);

	for (i = 0; i < performanceCounters; i++)
	{
		size += strlen(performanceCounterList[i].name) + 1;
	}

	if (size <= buffSize)
	{
		int p = 0;
		for (i = 0; i < performanceCounters; i++)
		{
			int l = strlen(performanceCounterList[i].name) + 1;
			memcpy(buff + p, performanceCounterList[i].name, l);
			p += l;
		}
		buff[p] = 0;
	}

	kernelLockRelease(&performanceCounterListLock);

	return size;
}
